#ifndef __HASH_HPP
#define __HASH_HPP

#include <string_view>

/**
 * 这个哈希计算是从 entt 中提取出来的
*/

#if defined __clang__ || defined __GNUC__
#    define HASH_PRETTY_FUNCTION __PRETTY_FUNCTION__
#    define HASH_PRETTY_FUNCTION_PREFIX '='
#    define HASH_PRETTY_FUNCTION_SUFFIX ']'
#elif defined _MSC_VER
#    define HASH_PRETTY_FUNCTION __FUNCSIG__
#    define HASH_PRETTY_FUNCTION_PREFIX '<'
#    define HASH_PRETTY_FUNCTION_SUFFIX '>'
#endif

#define HASH_OFFSET 14695981039346656038ULL
#define HASH_PRIME  1099511628211ULL

namespace Utils::Hash
{
    template<typename Type>
    [[nodiscard]] constexpr auto ToTypeName() noexcept 
    {
    #if defined HASH_PRETTY_FUNCTION
        std::string_view pretty_function{HASH_PRETTY_FUNCTION};
        auto first = pretty_function.find_first_not_of(' ', pretty_function.find_first_of(HASH_PRETTY_FUNCTION_PREFIX) + 1);
        auto value = pretty_function.substr(first, pretty_function.find_last_of(HASH_PRETTY_FUNCTION_SUFFIX) - first);
        return value;
    #else
        #error "编译器不支持，请自行实现";
    #endif
    }

    template<typename Type>
    [[nodiscard]] constexpr size_t GetTypeHash() noexcept 
    {
        const auto &typeStr = ToTypeName<std::remove_cv_t<std::remove_reference_t<Type>>>();
        size_t hash = HASH_OFFSET;
        for(const auto value : typeStr)
        {
            hash = (hash ^ static_cast<size_t>(value)) * HASH_PRIME;
        }
        return hash;
    }

    template<typename Type>
    [[nodiscard]] constexpr size_t GetTypeHash(Type &&) noexcept 
    {
        return GetTypeHash<std::remove_cv_t<std::remove_reference_t<Type>>>();
    }

}

#endif
